package com.gin.utils

import com.typesafe.config.{Config, ConfigFactory}
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.fs.{FSDataInputStream, FileSystem, Path}
import org.apache.log4j.Logger
import java.io.{File, InputStreamReader}
import java.nio.file.Files


object Configs {
  private[this] val LOG = Logger.getLogger(this.getClass)

  def parser(args: Array[String], programName: String): Option[Argument] = {
    val parser = new scopt.OptionParser[Argument](programName) {
      head(programName, "1.0.0")

      opt[String]('c', "config")
        .required()
        .valueName("fileName")
        .action((x, c) => c.copy(filePath = x))
        .text("com.gin.nebula.NebulaClientExecutor fileName")

      opt[String]("nGql")
        .valueName("statement")
        .action((x, c) => c.copy(statement = x))
        .text("executor statement")

    }
    parser.parse(args, Argument())
  }

  /**
   *
   * @param configPath
   * @return
   */
  def parse(configPath: String): Configs = {
    var config: Config = null
    if (configPath.startsWith("hdfs://")) {
      val hadoopConfig: Configuration = new Configuration()
      val fs: FileSystem = org.apache.hadoop.fs.FileSystem.get(hadoopConfig)
      val file: FSDataInputStream = fs.open(new Path(configPath))
      val reader = new InputStreamReader(file)
      config = ConfigFactory.parseReader(reader)
    } else {
      if (!Files.exists(new File(configPath).toPath)) {
        throw new IllegalArgumentException(s"${configPath} not exist")
      }
      config = ConfigFactory.parseFile(new File(configPath))
    }

    //nebula连接配置
    val nebulaConf = config.getConfig("nebula")
    val graphAddress = nebulaConf.getString("address.graph")
    val timeout = nebulaConf.getInt("timeout")
    val user = nebulaConf.getString("user")
    val pwd = nebulaConf.getString("pwd")
    val space = nebulaConf.getString("space")

    //nebula 查询语句
    val nGqlConf = config.getConfig("nGql")
    val nGql = nGqlConf.getString("statement")
    val timeWait = nGqlConf.getLong("timeWait")

    val nebulaDatabaseEntry = NebulaDatabaseEntry(graphAddress, timeout, user, pwd, space)
    val nebulaExecutorEntry = NebulaExecutorEntry(nGql, timeWait)
    LOG.info(s"config ${config}")
    Configs(nebulaDatabaseEntry, nebulaExecutorEntry)
  }

}

/**
 * 参数封装对象
 * @param filePath 文件路径
 * @param statement nebula graph 执行语句
 */
final case class Argument(filePath: String = "nebula_client.conf",
                          statement: String = ""
                         ){
  override def toString: String =
    s"Argument:{" +
      s"filePath=$filePath, " +
      s"statement=$statement}"
}

/**
 * Configs 配置对象
 */
case class Configs(nebulaConfig: NebulaDatabaseEntry,
                   executorConfig: NebulaExecutorEntry){

  override def toString: String =
  s"Configs:{" +
    s"nebulaConfig=$nebulaConfig, " +
    s"executorConfig=$executorConfig}"
}

/**
 * nebula
 * @param graphAddress graphd 地址
 * @param user 用户名
 * @param pwd 密码
 * @param space 图空间
 */
case class NebulaDatabaseEntry(graphAddress: String,
                               timeout: Int,
                               user: String,
                               pwd: String,
                               space: String) {
  require(graphAddress.trim.nonEmpty, "nebula.address.graph cannot be empty")
  require(timeout > 0, "nebula.timeout cannot be negative number")
  require(user.trim.nonEmpty, "nebula.user cannot be empty")
  require(pwd.trim.nonEmpty, "nebula.space cannot be empty")
  require(space.trim.nonEmpty, "nebula.pwd cannot be empty")

  override def toString: String =
    s"NebulaDatabaseEntry:{" +
      s"graphAddress=$graphAddress, " +
      s"timeout=$timeout, " +
      s"user=$user, " +
      s"pwd=$pwd, " +
      s"space=$space}"

}

/**
 * nebula
 * @param nGql 查询语句-可选
 */
case class NebulaExecutorEntry(nGql: String,
                               timeWait: Long) {
  override def toString: String =
    s"NebulaExecutorEntry:{" +
      s"waitTime=$timeWait,"
      s"nGql=$nGql}"
}

